'''
Created on Nov 19, 2010

@author: dexen
'''

import time
import multiprocessing as mp
from multiprocessing.queues import Queue

from dexen.system.common.meta import JobMeta
from dexen.system.node.slave.comm import InUnit, OutUnit
from dexen.system.common.transact import SlaveRecvTransact
from dexen.system.node.slave.executor import SlaveTaskExecutor




#===============================================================================
# SlaveCore
#===============================================================================
class SlaveCore(mp.Process):
    def __init__(self, comm):
        mp.Process.__init__(self)
        self.comm = comm
        self.executors = {} # job_id:SlaveTaskExecutor
        self.jobs = {} # job_id:JobMeta
        self.queues = {} # job_id : dict('in', 'out')

    def _create_executor(self, job_id):
        job_meta = self.jobs[job_id]
        assert isinstance(job_meta, JobMeta)
        inq, outq = mp.Queue(1), mp.Queue(1)
        self.queues[job_id] = {"in":inq, "out":outq}
        executor = SlaveTaskExecutor(job_meta, inq, outq)
        self.executors[job_id] = executor
        return executor


    def _update_jobs(self):
        job_metas = self.comm.get_jobs()
        for job_meta in job_metas:
            assert isinstance(job_meta, JobMeta)
            job_id = job_meta.get_id()
            self.jobs[job_id] = job_meta
            executor = self._create_executor(job_id)
            executor.start()
            print "slave.core I have created executor for ", job_meta.get_id(), job_meta.get_name()
        """
        for executor in self.executors.values():
            assert isinstance(executor, SlaveTaskExecutor)
            if executor.expired():
                executor.terminate()
        """

    def _get_executor(self, job_id):
        print "checking if executor has key", job_id 
        assert self.executors.has_key(job_id)
        executor = self.executors[job_id]
        assert isinstance(executor, SlaveTaskExecutor)
        if not executor.is_alive():
            del self.executors[job_id]
            del self.queues[job_id]
            print "Recreating the job:", job_id
            executor = self._create_executor(job_id)
            executor.start()
        return executor
   
    def _update_transact(self):
        unit = self.comm.get_in_unit()
        if unit == None: return
        assert isinstance(unit, InUnit)
        job_id = unit.job_id
        executor = self._get_executor(job_id)    
        assert isinstance(executor, SlaveTaskExecutor)
        in_q = self.queues[job_id]["in"]
        out_q = self.queues[job_id]["out"]
        assert isinstance(in_q, Queue)
        assert isinstance(out_q, Queue)
        in_q.put(unit)
        #while True:
            #transact = out_q.get_nowait()
            #if not transact: break
            #time.sleep(0.1)
        transact = out_q.get()
        assert isinstance(transact, SlaveRecvTransact)
        self.comm.set_out_unit(OutUnit(job_id, transact))
        executor.terminate()
            
    def run(self):
        while True:
            self._update_jobs()
            self._update_transact()
            time.sleep(1)
    
